package thread

import (
	"codejy/globalfunc"
	"codejy/store"
	"codejy/structdef"
	"codejy/typedefault"
	"codejy/utils"
	"fmt"
	"os"
	"strings"
	"sync"
)

// 所有线程等待集合，用于主线程等待所有线程执行完毕
var ThreadAllWait = sync.WaitGroup{}

func GetThreadAllWait() *sync.WaitGroup {
	return &ThreadAllWait
}

type Thread struct {
	Addr            string                    // 实例地址  线程实例
	ThreadStore     *structdef.ThreadStore    //当前环境的线程数据 （父）
	CurrentThread   *structdef.ThreadStore    // 子线程
	CurrentThreadId string                    // 子线程id
	FuncDef         *structdef.FuncDefinition // 当前线程执行的函数定义
	FunParameter    []string                  //函数参数
	IsRun           bool                      //执行状态,是否执行完毕
}

// 创建实例
func (a *Thread) CreateTypeDefault(addr string, threadStore *structdef.ThreadStore, parameter ...string) {

	addrList := parameter[0]
	funcArgs, b := typedefault.GetTypeDefaultValue[[]string](threadStore, "List", addrList)
	if !b {
		panic("错误::::::参数错误")
	}
	if len(funcArgs) == 0 {
		panic("错误::::::第一个参数不能为空,必须是函数名称")
	}
	funcName := funcArgs[0] //函数名称
	//排除前后""
	if strings.HasPrefix(funcName, "\"") && strings.HasSuffix(funcName, "\"") {
		funcName = funcName[1 : len(funcName)-1]
	}
	if len(funcArgs) > 1 {
		funcArgs = funcArgs[1:] //函数参数
	} else {
		funcArgs = []string{}
	}
	//获取函数定义,函数定义是在当前文件中定义的
	definition := store.SearchFunDefinition(threadStore, funcName)
	if definition == nil {
		panic("错误::::::函数未定义:" + funcName)
	}
	//创建线程,的子线程环境
	newThreadId, newThreadStore := store.CopyThread(threadStore, definition.Body, 0, definition.Name)

	instance := &Thread{
		Addr:            addr,
		ThreadStore:     threadStore,
		CurrentThread:   newThreadStore,
		CurrentThreadId: newThreadId,
		FuncDef:         definition,
		FunParameter:    funcArgs,
		IsRun:           false,
	}
	store.AddTypeDefaultInstanceStore(threadStore, a.GetTypeName(), addr, instance)
}

func (a *Thread) GetData() interface{} {
	return a
}

func (a *Thread) ToStr() string {
	return fmt.Sprintf("线程id%s,线程执行的函数:%s,", a.ThreadStore.ThreadId, a.FuncDef.Name)
}

func (a *Thread) ParameterProcessing(parameter []string) []string {
	//排除前后""
	for i := range parameter {
		s := parameter[i]
		if strings.HasPrefix(s, "\"") && strings.HasSuffix(s, "\"") {
			s = s[1 : len(s)-1]
			parameter[i] = s
		}
	}
	return parameter
}

func (a *Thread) AddArgument(list string) {
	funcArgs, b := typedefault.GetTypeDefaultValue[[]string](a.ThreadStore, "List", list)
	if !b {
		panic("错误::::::参数错误")
	}
	a.FunParameter = append(a.FunParameter, funcArgs...)
}

// 执行线程函数,返回派生线程id
func (f *Thread) ThreadRun() {
	//如果线程已经执行完毕,就不执行
	if f.IsRun {
		panic("错误::::::此线程已经执行过了,不能重复执行,线程id:" + f.CurrentThreadId)
	}
	f.IsRun = true
	//启动线程
	ThreadAllWait.Add(1)
	go func() {
		defer func() {
			if err := recover(); err != nil {
				//删除线程里产生的变量
				store.DeleteThreadStore(f.CurrentThreadId)
				//打印线程报错信息
				store.PrintExecuteCodeRecordLog(f.CurrentThread, err)
				os.Exit(1) //退出程序
			}
		}()
		globalfunc.ExecuteFunc("FunLineExecute", f.CurrentThread, f.FuncDef.Body, "", f.FuncDef.Name, f.FunParameter)
		//如果线程没有被停止,并且线程没有等待,就删除线程里产生的变量,和线程环境
		//线程执行完毕,删除线程里产生的变量,和线程环境
		//线程执行完毕,删除线程里产生的变量
		store.DeleteThreadStore(f.CurrentThreadId)
		//线程执行完毕后,打印线程执行过程
		if utils.Debug {
			store.PrintExecuteCodeRecordLog(f.CurrentThread, nil)
		}
		ThreadAllWait.Done()

	}()
}

// 获取线程id
func (f *Thread) GetThreadId() string {
	return f.CurrentThreadId
}

func (f *Thread) GetDef() string {
	return `
		@CodeManual(def="new("Thread","函数定义")",des="创建线程实例")
		type Thread{
			def init{
				core&CreateTypeDefault($realArgs)
			}
		
			@CodeManual(def="addArgs($realArgs)",des="给线程函数添加参数")
			def addArgs{
				core&AddArgument($realArgs)
			}

			@CodeManual(def="getId()",des="获取当前线程id")
			def getId{
				to core&GetThreadId()
			}

			@CodeManual(def="start()",des="启动子线程")
			def start{
				core&ThreadRun()
			}

		}
	`
}
func init() {
	typedefault.RegisterTypeDefault(&Thread{})
	globalfunc.RegisterFuncAll("GetThreadAllWait", GetThreadAllWait)
	globalfunc.RegisterFuncAll("NewThreadInside", NewThreadInside)
}

func (f *Thread) GetTypeName() string {
	return "Thread"
}

// 线程状态翻译
func (f *Thread) GetThreadStatus(status int) string {
	switch status {
	case 0:
		return "未启动"
	case 1:
		return "运行中"
	case 2:
		return "阻塞"
	case 3:
		return "结束"
	}
	return "未知"
}

func NewThreadInside(threadStore *structdef.ThreadStore, funName string, funArgs []string) {

	//获取函数定义,函数定义是在当前文件中定义的
	definition := store.SearchFunDefinition(threadStore, funName)
	if definition == nil {
		panic("函数" + funName + "未定义")
	}
	newThreadId, newThreadStore := store.CopyThread(threadStore, definition.Body, 0, definition.Name)
	ThreadAllWait.Add(1) //添加一个线程
	go func() {
		defer func() {
			if err := recover(); err != nil {
				//删除线程里产生的变量
				store.DeleteThreadStore(newThreadId)
				store.PrintExecuteCodeRecordLog(newThreadStore, err)
				os.Exit(1)
			}
		}()
		globalfunc.ExecuteFunc("FunLineExecute", newThreadStore, definition.Body, "", definition.Name, funArgs)
		//如果线程没有被停止,并且线程没有等待,就删除线程里产生的变量,和线程环境
		//线程执行完毕,删除线程里产生的变量,和线程环境
		store.DeleteThreadStore(newThreadId)
		//线程执行完毕后,打印线程执行过程
		if utils.Debug {
			store.PrintExecuteCodeRecordLog(newThreadStore, nil)
		}
		ThreadAllWait.Done()
	}()

}
